// Code by Matheus Lin
// While developing a version of "Chain Reaction", I ended up on
// those "fireworks-like" things. I leave it to you here.
// Chain Reaction coming up next!

// Configs

var screenWidth = window.innerWidth;
var screenHeight = window.innerHeight;
var controller;

var minVx = -10;
var deltaVx = 20;
var minVy = 25
var deltaVy = 15;
var minParticleV = 5;
var deltaParticleV = 5;

var gravity = 1;

var explosionRadius = 200;
var bombRadius = 10;
var explodingDuration = 100;
var explosionDividerFactor = 10; // I couldn't find a better name. Got any?

var nBombs = 1; // initial
var percentChanceNewBomb = 5;

// Color utils forked from http://andreasstorm.com/
// (or someone who forked from there)

function Color(min) {
	this.style = 'hsla(' + (Math.random() * 255) + ', 100%, 50%, 1.0)';
};

function colorValue(min) {
	return Math.floor(Math.random() * (255 - min) + min);
}

function createColorStyle(r, g, b) {
	return 'rgba(' + r + ',' + g + ',' + b + ', 0.8)';
}

// A Bomb. Or firework.
function Bomb() {
	var self = this;
	self.radius = bombRadius;
	self.previousRadius = bombRadius;
	self.explodingDuration = explodingDuration;
	self.hasExploded = false;
	self.alive = true;
	self.color = new Color(160);

	self.px = (window.innerWidth / 4) + (Math.random() * window.innerWidth / 2);
	self.py = window.innerHeight;
	self.vx = minVx + Math.random() * deltaVx;
	self.vy = (minVy + Math.random() * deltaVy) * -1;

	self.duration = 
		self.update = function(particlesVector) {
		if (self.hasExploded) {
			var deltaRadius = explosionRadius - self.radius;
			self.previousRadius = self.radius;
			self.radius += deltaRadius / explosionDividerFactor;
			self.explodingDuration--;
			if (self.explodingDuration == 0) {
				self.alive = false;
			}
		} else {
			self.vx += 0;
			self.vy += gravity;
			if (self.vy >= 0) { // invertion point
				self.explode(particlesVector);
			}
			self.px += self.vx;
			self.py += self.vy;
		}
	};

	self.draw = function(ctx) {
		ctx.beginPath();
		ctx.arc(self.px, self.py, self.previousRadius, 0, Math.PI * 2, false);
		if (self.hasExploded) {
		} else {
			ctx.fillStyle = self.color.style;
			ctx.lineWidth = 1;
			ctx.fill();
		}
	};

	self.explode = function(particlesVector) {
		self.hasExploded = true;
		var e = 3 + Math.floor(Math.random() * 3);
		for(var j = 0; j < e; j++) {
			var n = 10 + Math.floor(Math.random() * 21); // 10 - 30
			var speed = minParticleV + Math.random() * deltaParticleV;
			var deltaAngle = 2 * Math.PI / n;
			var initialAngle = Math.random() * deltaAngle;
			for(var i = 0; i < n; i++) {
				particlesVector.push(new Particle(self,  i * deltaAngle + initialAngle, speed));
			}
		}
	};

}

function Particle(parent, angle, speed) {
	var self = this;
	self.px = parent.px;
	self.py = parent.py;
	self.vx = Math.cos(angle) * speed;
	self.vy = Math.sin(angle) * speed;
	self.color = parent.color;
	self.duration = 40 + Math.floor(Math.random() * 20);
	self.alive = true;

	self.update = function(){
		self.vx += 0;
		self.vy += gravity / 10;

		self.px += self.vx;
		self.py += self.vy;
		self.radius = 3;

		self.duration--;
		if(self.duration <= 0){
			self.alive = false;
		}
	};

	self.draw = function(ctx) {
		ctx.beginPath();
		ctx.arc(self.px, self.py, self.radius, 0, Math.PI * 2, false);
		ctx.fillStyle = self.color.style;
		ctx.lineWidth = 1;
		ctx.fill();
	};
}

function Controller() {
	var self = this;
	self.canvas = document.getElementById("screen");
	self.canvas.width = screenWidth;
	self.canvas.height = screenHeight;
	self.ctx = self.canvas.getContext('2d');
	
	function setSpeedParams() {
		var heightReached = 0;
		var vy = 0;
		while (heightReached < screenHeight && vy >= 0){
			vy += gravity;
			heightReached += vy;
		}
		minVy = vy / 2;
		deltaVy = vy - minVy;
		vx = (1 / 4) * screenWidth / (vy / 2);
		minVx = -vx;
		deltaVx = 2*vx;
	};
	
	self.resize = function() {
		screenWidth = window.innerWidth;
		screenHeight = window.innerHeight;
		self.canvas.width = screenWidth;
		self.canvas.height = screenHeight;
		setSpeedParams();
	};
	
	self.resize();
	window.onresize = self.resize;
	self.init = function(){
		self.readyBombs = [];
		self.explodedBombs = [];
		self.particles = [];
		for(var i = 0; i < nBombs; i++){
			self.readyBombs.push(new Bomb());
		}
	}
	
	self.update = function(){
		var aliveBombs = [];
		while(self.explodedBombs.length > 0){
			var bomb = self.explodedBombs.shift();
			bomb.update();
			if (bomb.alive) {
				aliveBombs.push(bomb);
			}
		}
		self.explodedBombs = aliveBombs;
		var notExplodedBombs = [];
		while (self.readyBombs.length > 0) {
			var bomb = self.readyBombs.shift();
			bomb.update(self.particles);
			if (bomb.hasExploded){
				self.explodedBombs.push(bomb);
			} else {
				notExplodedBombs.push(bomb);
			}
		}
		self.readyBombs = notExplodedBombs;
		var aliveParticles = [];
		while (self.particles.length > 0) {
			var particle = self.particles.shift();
			particle.update();
			if (particle.alive){
				aliveParticles.push(particle);
			}
		}
		self.particles = aliveParticles;
	}

	self.draw = function() {
		self.ctx.beginPath();
		self.ctx.fillStyle='rgba(0, 0, 0, 0.1)'; // Ghostly effect
		self.ctx.fillRect(0, 0, self.canvas.width, self.canvas.height);
		self.ctx.globalCompositeOperation = 'lighter';
		for (var i = 0; i < self.readyBombs.length; i++){
			self.readyBombs[i].draw(self.ctx);
		}
		for (var i = 0; i < self.explodedBombs.length; i++){
			self.explodedBombs[i].draw(self.ctx);
		}
		for (var i = 0; i < self.particles.length; i++){
			self.particles[i].draw(self.ctx);
		}
		self.ctx.globalCompositeOperation = 'source-over';
	}
	
	self.animation = function() {
		self.update();
		self.draw();
		if (Math.random() * 100 < percentChanceNewBomb) {
			self.readyBombs.push(new Bomb());
		}
		requestAnimationFrame(self.animation);
	}
}

var controller = new Controller();
controller.init();
requestAnimationFrame(controller.animation);